package com.vinjogames.entities;


import com.vinjogames.gfx.Gun;
import com.vinjogames.util.MemoryManager;
import com.vinjogames.util.VectorF;


/**
 * 
 * AttackObject is the base class for units and turrets. This represents objects that are capable of moving, aiming,
 * attacking, and performing specialty duties.
 * 
 * @author Joey
 *
 */
public abstract class AttackObject extends GameObject{
	public static float MAX_FORCE = 15.0f;
	public static float MIN_FORCE = 1.0f;
	
	protected int attackType;
	protected int attackCost;
	protected boolean direction;//true = right
	protected boolean hasFired;
	protected boolean inAttackMode;
	protected float attackDamage;
	protected float attackRadius;
	protected float attackForceMax;
	protected float minAttackAngle;
	protected float maxAttackAngle;
	protected float mRotation;
	protected float attackVariance;
	protected Player myPlayer; //TODO: Decide if we need to remove all the player references to speed up the game.
	protected Gun mGun;
	
	protected float currentForce;
	
	public AttackObject(int type, int cost) {
		super(type);
		currentForce = 0;
		attackVariance = 6.0f;
		inAttackMode = false;
		attackCost = cost;
	}
	
	
	/**
	 * Puts the attack object into an attacking state. There are exceptions where certain units (which inherit attack object)
	 * are not allowed to attack. These units will have 0 attackDamage and therefore cannot enter attack mode. 
	 */
	public void enterAttackMode() { if(attackDamage > 0.0f) inAttackMode = true; }
	public void exitAttackMode() { inAttackMode = false; }
	
	
	/**
	 * @param large
	 * @param up
	 */
	public void incrementCurrentForce(boolean large, boolean up){
		if(!inAttackMode) return;
		if(large)
			if(up)
				currentForce = currentForce + 1 > MAX_FORCE ? MAX_FORCE : currentForce + 1;
			else currentForce = currentForce - 1 < MIN_FORCE ? MIN_FORCE : currentForce - 1;
		else {
			if(up)
				currentForce = currentForce + 0.1f > MAX_FORCE ? MAX_FORCE : currentForce + 0.1f;
			else currentForce = currentForce - 0.1f < MIN_FORCE ? MIN_FORCE : currentForce - 0.1f;
		}	
	}

	
	/**
	 * @param attackPoints
	 * @return
	 */
	public Projectile fireCannon(int attackPoints){
		if(!inAttackMode || attackPoints > attackCost || hasFired || !myPlayer.purchaseGeneric(attackPoints))  return null;
		
		hasFired = true;
		return MemoryManager.getInstance().getNewProjectile(this, getGun().calculateMuzzleLocation(),
				getWeaponVector(currentForce), attackPoints, attackDamage);
	}

	public VectorF getWeaponVector(float tempForce){
		float variance = (float) (attackVariance * 0.5f - Math.random() * attackVariance);
		float radians = (float)Math.toRadians(getGun().getAngle() + mRotation + variance);
		float dX = (float)Math.cos(radians);
		float dY = (float)Math.sin(radians);
		float xForce = direction ? tempForce : -tempForce;
		return new VectorF(xForce * dX,tempForce * dY);
	}
	
	public Gun getGun(){ return mGun; }
	
	//Getters and Setters.
	public boolean getDirection(){ return direction; }
	public float getCurrentForce() { return currentForce; }
	public void setCurrentForce(float currentForce) { this.currentForce = currentForce; }
	public int getAttackType() { return attackType;	}
	public void setAttackType(int attackType) {	this.attackType = attackType; }
	public int getAttackCost() { return attackCost;	}
	public void setAttackCost(int attackCost) {	this.attackCost = attackCost; }
	public boolean isDirection() { return direction; }
	public void setDirection(boolean direction) { this.direction = direction; }
	public float getAttackDamage() { return attackDamage; }
	public void setAttackDamage(float attackDamage) { this.attackDamage = attackDamage;	}
	public float getAttackRadius() { return attackRadius; }
	public void setAttackRadius(float attackRadius) { this.attackRadius = attackRadius;	}
	public float getAttackForceMax() { return attackForceMax; }
	public void setAttackForceMax(float attackForceMax) { this.attackForceMax = attackForceMax;	}
	public float getMinAttackAngle() { return minAttackAngle; }
	public void setMinAttackAngle(float minAttackAngle) { this.minAttackAngle = minAttackAngle;	}
	public float getMaxAttackAngle() { return maxAttackAngle; }
	public void setMaxAttackAngle(float maxAttackAngle) { this.maxAttackAngle = maxAttackAngle;	}
	public Player getMyPlayer() { return myPlayer; }
	public void setMyPlayer(Player myPlayer) { this.myPlayer = myPlayer; }
	public float getAttackVariance() { return attackVariance; }
	public void setAttackVariance(float attackVariance) { this.attackVariance = attackVariance; }
	public boolean hasFired() { return hasFired; }
	public void clearFired() { hasFired = false; }
	public float getRotation() { return mRotation; }
	public boolean isInAttackMode() { return inAttackMode; }
	public boolean canAim() { return attackVariance > 0.0f ? true : false; } 
}
